/*
	Copyright (C) 2010 2011 Rémi Thebault

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <procycle/link.h>
#include <procycle/task.h>
#include <procycle/cycle.h>


namespace PC {

Link::Link(Task* from, Task* to, Type type, int lag) :
	m_cycle(from->cycle()),
	m_taskFrom(from),
	m_taskTo(to),
	m_type(type),
	m_lag(lag)
{
	m_cycle->connectLink(this);
}

Link::Link(Cycle *cycle) :
	m_cycle(cycle)
{
	m_cycle->connectLink(this);
}

Link::~Link() {
	m_cycle->disconnectLink(this);
}



void Link::setTaskFrom(Task *taskFrom) {
	m_taskFrom->unregisterOutLink(this);
	m_taskFrom = taskFrom;
}

void Link::setTaskTo(Task *taskTo) {
	m_taskTo->unregisterInLink(this);
	m_taskTo = taskTo;
}


void Link::registerToTasks() {
	m_taskFrom->registerOutLink(this);
	m_taskTo->registerInLink(this);
}


void Link::setLag(int lag) {
	m_lag = lag;
	m_cycle->schedule();
}


int Link::timeFrom() {
	switch (m_type) {
	case TYPE_FS:
	case TYPE_SS:
		return m_taskTo->start() - m_lag;
	case TYPE_FF:
	case TYPE_SF:
		return m_taskTo->finish() - m_lag;
	}
	return 0;
}

int Link::timeTo() {
	switch (m_type) {
	case TYPE_FS:
	case TYPE_FF:
		return m_taskFrom->finish() + m_lag;
	case TYPE_SS:
	case TYPE_SF:
		return m_taskFrom->start() + m_lag;
	}
	return 0;
}


int Link::lateTimeFrom() {
	switch (m_type) {
	case TYPE_FS:
	case TYPE_SS:
		return m_taskTo->lateStart() - m_lag;
	case TYPE_FF:
	case TYPE_SF:
		return m_taskTo->lateFinish() - m_lag;
	}
	return 0;
}

int Link::lateTimeTo() {
	switch (m_type) {
	case TYPE_FS:
	case TYPE_FF:
		return m_taskFrom->lateFinish() + m_lag;
	case TYPE_SS:
	case TYPE_SF:
		return m_taskFrom->lateStart() + m_lag;
	}
	return 0;
}



bool Link::isCriticalPath() {
	return m_taskFrom->isCriticalPath() && m_taskTo->isCriticalPath();
}



void
Link::loadFromElement(const QDomElement& element) {
	XmlStorable::loadFromElement(element);
	m_type = string_to_type(element.attribute("type"));
	m_taskFrom = m_cycle->resolvAbsoluteTask(element.attribute("taskFrom"));
	m_taskTo = m_cycle->resolvAbsoluteTask(element.attribute("taskTo"));
	registerToTasks();
	bool ok;
	m_lag = element.attribute("lag").toInt(&ok);
	if (!ok) {
		throw XmlFormatError();
	}
}

QDomElement
Link::saveToElement(QDomDocument& doc) const {
	QDomElement element = XmlStorable::saveToElement(doc);
	element.setAttribute("type", type_to_string());
	element.setAttribute("taskFrom", m_taskFrom->tbsId());
	element.setAttribute("taskTo", m_taskTo->tbsId());
	element.setAttribute("lag", m_lag);
	return element;
}

}
